﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Timers;
using DataService.Enums;
using DataService.Interfaces;
using DataService.Structs;
using DataService.Tag;

namespace DataService.Group;

public class PLCGroup : IGroup
{
    protected Timer _timer;

    protected bool _isActive;
    public virtual bool IsActive
    {
        get
        {
            return _isActive;
        }
        set
        {
            _isActive = value;
            if (value)
            {
                if (_updateRate <= 0) _updateRate = 100;
                _timer.Interval = _updateRate;
                _timer.Elapsed += new ElapsedEventHandler(timer_Timer);
                _timer.Start();
            }
            else
            {
                _timer.Elapsed -= new ElapsedEventHandler(timer_Timer);
                _timer.Stop();
            }
        }
    }

    protected short _id;
    public short ID
    {
        get
        {
            return _id;
        }
    }

    protected int _updateRate;
    public int UpdateRate
    {
        get
        {
            return _updateRate;
        }
        set
        {
            _updateRate = value;
        }
    }

    protected string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }

    protected float _deadband;
    public float DeadBand
    {
        get
        {
            return _deadband;
        }
        set
        {
            _deadband = value;
        }
    }


    protected ICache _cacheReader;

    protected IPLCDriver _plcReader;
    public IDriver Parent
    {
        get
        {
            return _plcReader;
        }
    }

    protected List<int> _changedList;
    public List<int> ChangedList
    {
        get
        {
            return _changedList;
        }
    }


    protected List<TagBase> _items;
    public IEnumerable<TagBase> Items
    {
        get { return _items; }
    }

    protected IDataServer _server;
    public IDataServer Server
    {
        get
        {
            return _server;
        }
    }

    protected List<PDUArea> _rangeList = new List<PDUArea>();

    protected PLCGroup()
    {
    }

    public PLCGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
    {
        _id = id;
        _name = name;
        _updateRate = updateRate;
        _isActive = active;
        _plcReader = plcReader;
        _server = _plcReader.Parent;
        _changedList = new List<int>();
        _cacheReader = new ByteCacheReader();
        _timer = new Timer();
    }

    public bool AddItems(IList<TagMetaData> items)
    {
        int count = items.Count;
        if (_items == null) _items = new List<TagBase>(count);
        lock (_server.SyncRoot)
        {
            for (int i = 0; i < count; i++)
            {
                TagBase dataItem = null;
                TagMetaData meta = items[i];
                if (meta.GroupID == _id)
                {
                    DeviceAddress addr = _plcReader.GetDeviceAddress(meta.Address);
                    if (addr.DataSize == 0) addr.DataSize = meta.Size;
                    if (addr.VarType == DataType.NONE) addr.VarType = meta.DataType;
                    if (addr.VarType != DataType.BOOL) addr.Bit = 0;
                    switch (meta.DataType)
                    {
                        case DataType.BOOL:
                            dataItem = new BoolTag(meta.ID, addr, this);
                            break;
                        case DataType.BYTE:
                            dataItem = new ByteTag(meta.ID, addr, this);
                            break;
                        case DataType.WORD:
                            dataItem = new UShortTag(meta.ID, addr, this);
                            break;
                        case DataType.SHORT:
                            dataItem = new ShortTag(meta.ID, addr, this);
                            break;
                        case DataType.DWORD:
                            dataItem = new UIntTag(meta.ID, addr, this);
                            break;
                        case DataType.INT:
                            dataItem = new IntTag(meta.ID, addr, this);
                            break;
                        case DataType.FLOAT:
                            dataItem = new FloatTag(meta.ID, addr, this);
                            break;
                        case DataType.STR:
                            dataItem = new StringTag(meta.ID, addr, this);
                            break;
                    }
                    if (dataItem != null)
                    {
                        //dataItem.Active = meta.Active;
                        _items.Add(dataItem);
                        _server.AddItemIndex(meta.Name, dataItem);
                    }
                }
            }
        }
        _items.TrimExcess();
        _items.Sort();
        UpdatePDUArea();
        return true;
    }

    public bool AddTags(IEnumerable<TagBase> tags)
    {
        if (_items == null)
        {
            _items = new List<TagBase>();
        }
        foreach (TagBase tag in tags)
        {
            if (tag != null)
            {
                _items.Add(tag);
            }
        }
        _items.TrimExcess();
        _items.Sort();
        UpdatePDUArea();
        return true;
    }

    public bool RemoveItems(params TagBase[] items)
    {
        foreach (var item in items)
        {
            _server.RemoveItemIndex(item.GetTagName());
            _items.Remove(item);
        }
        UpdatePDUArea();
        return true;
    }

    protected void UpdatePDUArea()
    {
        int count = _items.Count;
        if (count > 0)
        {
            DeviceAddress _start = _items[0].Address;
            _start.Bit = 0;
            int bitCount = _cacheReader.ByteCount;
            if (count > 1)
            {
                int cacheLength = 0;//缓冲区的大小
                int cacheIndexStart = 0;
                int startIndex = 0;
                DeviceAddress segmentEnd = DeviceAddress.Empty;
                DeviceAddress tagAddress = DeviceAddress.Empty;
                DeviceAddress segmentStart = _start;
                for (int j = 1, i = 1; i < count; i++, j++)
                {
                    tagAddress = _items[i].Address;//当前变量地址 
                    int offset1 = _cacheReader.GetOffset(tagAddress, segmentStart);
                    if (offset1 > (_plcReader.PDU - tagAddress.DataSize) / bitCount)
                    {
                        segmentEnd = _items[i - 1].Address;
                        int len = _cacheReader.GetOffset(segmentEnd, segmentStart);
                        len += segmentEnd.DataSize <= bitCount ? 1 : segmentEnd.DataSize / bitCount;
                        tagAddress.CacheIndex = (ushort)(cacheIndexStart + len);
                        _items[i].Address = tagAddress;
                        _rangeList.Add(new PDUArea(segmentStart, len, startIndex, j));
                        startIndex += j; j = 0;
                        cacheLength += len;//更新缓存长度
                        cacheIndexStart = cacheLength;
                        segmentStart = tagAddress;//更新数据片段的起始地址
                    }
                    else
                    {
                        tagAddress.CacheIndex = (ushort)(cacheIndexStart + offset1);
                        _items[i].Address = tagAddress;
                    }
                    if (i == count - 1)
                    {
                        segmentEnd = _items[i].Address;
                        int segmentLength = _cacheReader.GetOffset(segmentEnd, segmentStart);
                        if (segmentLength > (_plcReader.PDU - segmentEnd.DataSize) / bitCount)
                        {
                            segmentEnd = _items[i - 1].Address;
                            segmentLength = segmentEnd.DataSize <= bitCount ? 1 : segmentEnd.DataSize / bitCount;
                        }
                        tagAddress.CacheIndex = (ushort)(cacheIndexStart + segmentLength);
                        _items[i].Address = tagAddress;
                        segmentLength += segmentEnd.DataSize <= bitCount ? 1 : segmentEnd.DataSize / bitCount;
                        _rangeList.Add(new PDUArea(segmentStart, segmentLength, startIndex, j + 1));
                        cacheLength += segmentLength;
                    }
                }
                _cacheReader.Size = cacheLength;
            }
            else
            {
                var size = _start.DataSize <= bitCount ? 1 : _start.DataSize / bitCount;
                _rangeList.Add(new PDUArea(_start, size, 0, 1));
                _cacheReader.Size = size;//改变Cache的Size属性值将创建Cache的内存区域
            }
        }
    }

    public TagBase FindItemByAddress(DeviceAddress addr)
    {
        int index = _items.BinarySearch(new BoolTag(0, addr, null));
        return index < 0 ? null : _items[index];
    }

    public bool SetActiveState(bool active, params short[] items)
    {
        return false;
    }

    object sync = new object();
    protected void timer_Timer(object sender, EventArgs e)
    {
        if (_isActive)
        {
            lock (sync)
            {
                _changedList.Clear();
                Poll();
                if (_changedList.Count > 0)
                    Update();
            }
        }
        else
            return;
    }

    protected virtual void Poll()
    {
        if (_plcReader.IsClosed) return;
        byte[] cache = (byte[])_cacheReader.Cache;
        int offset = 0;
        foreach (PDUArea area in _rangeList)
        {
            byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据                
            if (rcvBytes == null)
            {
                //_plcReader.Connect();
                continue;
            }
            else
            {
                int index = area.StartIndex;//index指向_items中的Tag元数据
                int count = index + area.Count;
                while (index < count)
                {
                    DeviceAddress addr = _items[index].Address;
                    int iByte = addr.CacheIndex;
                    int iByte1 = iByte - offset;
                    if (addr.VarType == DataType.BOOL)
                    {
                        int tmp = rcvBytes[iByte1] ^ cache[iByte];
                        DeviceAddress next = addr;
                        if (tmp != 0)
                        {
                            while (addr.Start == next.Start)
                            {
                                if ((tmp & 1 << next.Bit) > 0) _changedList.Add(index);
                                if (++index < count)
                                    next = _items[index].Address;
                                else
                                    break;
                            }
                        }
                        else
                        {
                            while (addr.Start == next.Start && ++index < count)
                            {
                                next = _items[index].Address;
                            }
                        }
                    }
                    else
                    {
                        ushort size = addr.DataSize;
                        for (int i = 0; i < size; i++)
                        {
                            if (iByte1 + i < rcvBytes.Length && rcvBytes[iByte1 + i] != cache[iByte + i])
                            {
                                _changedList.Add(index);
                                break;
                            }
                        }
                        index++;
                    }
                }
                for (int j = 0; j < rcvBytes.Length; j++)
                    cache[j + offset] = rcvBytes[j];//将PLC读取的数据写入到CacheReader中
            }
            offset += rcvBytes.Length;
        }
    }

    protected void Update()
    {
        DateTime dt = DateTime.Now;
        if (DataChange != null)
        {
            HistoryData[] values = new HistoryData[_changedList.Count];
            int i = 0;
            foreach (int index in _changedList)
            {
                TagBase item = _items[index];
                var itemData = item.Read();
                if (item.Active)
                    item.Update(itemData, dt, QUALITIES.QUALITY_GOOD);
                if (_deadband == 0 || item.Address.VarType == DataType.FLOAT &&
                    Math.Abs(itemData.Single / item.Value.Single - 1) > _deadband)
                {
                    values[i].ID = item.ID;
                    values[i].Quality = item.Quality;
                    values[i].Value = itemData;
                    values[i].TimeStamp = item.Timestamp;
                    i++;
                }
            }
            foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
            {
                deleg.BeginInvoke(this, new DataChangeEventArgs(1, values), null, null);
            }
        }
        else
        {
            foreach (int index in _changedList)
            {
                TagBase item = _items[index];
                if (item.Active)
                    item.Update(item.Read(), dt, QUALITIES.QUALITY_GOOD);
            }
        }
    }

    public void Dispose()
    {
        if (_timer != null)
            _timer.Dispose();
        //if (_items != null)
        //    _items.Clear();
    }

    public virtual HistoryData[] BatchRead(DataSource source, bool isSync, params TagBase[] itemArray)
    {
        int len = itemArray.Length;
        HistoryData[] values = new HistoryData[len];
        if (source == DataSource.Device)
        {
            IMultiReadWrite multi = _plcReader as IMultiReadWrite;
            if (multi != null)
            {
                Array.Sort(itemArray);
                var itemArr = multi.ReadMultiple(Array.ConvertAll(itemArray, x => x.Address));
                for (int i = 0; i < len; i++)
                {
                    values[i].ID = itemArray[i].ID;
                    values[i].Value = itemArr[i].Value;
                    values[i].TimeStamp = itemArr[i].TimeStamp.ToDateTime();
                    itemArray[i].Update(itemArr[i].Value, values[i].TimeStamp, itemArr[i].Quality);
                }
            }
            else
            {
                for (int i = 0; i < len; i++)
                {
                    itemArray[i].Refresh(source);
                    values[i].ID = itemArray[i].ID;
                    values[i].Value = itemArray[i].Value;
                    values[i].Quality = itemArray[i].Quality;
                    values[i].TimeStamp = itemArray[i].Timestamp;
                }
            }
        }
        else
        {
            for (int i = 0; i < len; i++)
            {
                values[i].ID = itemArray[i].ID;
                values[i].Value = itemArray[i].Value;
                values[i].Quality = itemArray[i].Quality;
                values[i].TimeStamp = itemArray[i].Timestamp;
            }
        }
        return values;
    }

    public virtual int BatchWrite(SortedDictionary<TagBase, object> items, bool isSync = true)
    {
        int len = items.Count;
        int rev = 0;
        IMultiReadWrite multi = _plcReader as IMultiReadWrite;
        if (multi != null)
        {
            DeviceAddress[] addrs = new DeviceAddress[len];
            object[] objs = new object[len];
            int i = 0;
            foreach (var item in items)
            {
                addrs[i] = item.Key.Address;
                objs[i] = item.Value;
                i++;
            }
            rev = multi.WriteMultiple(addrs, objs);
        }
        else
        {
            foreach (var tag in items)
            {
                if (tag.Key.Write(tag.Value) < 0)
                    rev = -1;
            }
        }
        if (DataChange != null && rev >= 0)
        {
            HistoryData[] data = new HistoryData[len];
            int i = 0;
            foreach (var item in items)
            {
                TagBase tag = item.Key;
                data[i].ID = tag.ID;
                data[i].TimeStamp = tag.Timestamp;
                data[i].Quality = tag.Quality;
                data[i].Value = item.Key.ToStorage(item.Value);
                i++;
            }
            foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
            {
                deleg.BeginInvoke(this, new DataChangeEventArgs(1, data), null, null);
            }
        }
        return rev;
    }

    public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadInt32(address) : _plcReader.ReadInt32(address);
    }

    public ItemData<uint> ReadUInt32(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadUInt32(address) : _plcReader.ReadUInt32(address);
    }

    public ItemData<ushort> ReadUInt16(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadUInt16(address) : _plcReader.ReadUInt16(address);
    }

    public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadInt16(address) : _plcReader.ReadInt16(address);
    }

    public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadByte(address) : _plcReader.ReadByte(address);
    }

    public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadFloat(address) : _plcReader.ReadFloat(address);
    }

    public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        return source == DataSource.Cache ? _cacheReader.ReadBit(address) : _plcReader.ReadBit(address);
    }

    public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
    {
        ushort siz = address.DataSize;
        return source == DataSource.Cache ? _cacheReader.ReadString(address, siz) :
            _plcReader.ReadString(address, siz);
    }

    public int WriteInt32(DeviceAddress address, int value)
    {
        int rs = _plcReader.WriteInt32(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Int32=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteUInt32(DeviceAddress address, uint value)
    {
        int rs = _plcReader.WriteUInt32(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{DWord=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteUInt16(DeviceAddress address, ushort value)
    {
        int rs = _plcReader.WriteUInt16(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Word=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteInt16(DeviceAddress address, short value)
    {
        int rs = _plcReader.WriteInt16(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Int16=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteFloat(DeviceAddress address, float value)
    {
        int rs = _plcReader.WriteFloat(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Single=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteString(DeviceAddress address, string value)
    {
        int rs = _plcReader.WriteString(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,Storage.Empty, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteBit(DeviceAddress address, bool value)
    {
        int rs = _plcReader.WriteBit(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Boolean=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    public int WriteBits(DeviceAddress address, byte value)
    {
        int rs = _plcReader.WriteBits(address, value);
        if (rs >= 0)
        {
            if (DataChange != null)
            {
                TagBase tag = GetTagByAddress(address);
                if (tag != null)
                    DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
            {
                new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Byte=value}, DateTime.Now)
            }));
            }
        }
        return rs;
    }

    private TagBase GetTagByAddress(DeviceAddress addr)
    {
        int index = _items.BinarySearch(new BoolTag(0, addr, null));
        return index < 0 ? null : _items[index];
    }

    public event DataChangeEventHandler DataChange;
}


public struct PDUArea
{
    public DeviceAddress Start;
    public int Len;
    public int StartIndex;
    public int Count;

    public PDUArea(DeviceAddress start, int len, int startIndex, int count)
    {
        Start = start;
        Len = len;
        StartIndex = startIndex;
        Count = count;
    }
}

public sealed class NetBytePLCGroup : PLCGroup
{
    public NetBytePLCGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
    {
        _id = id;
        _name = name;
        _updateRate = updateRate;
        _isActive = active;
        _plcReader = plcReader;
        _server = _plcReader.Parent;
        _timer = new Timer();
        _changedList = new List<int>();
        _cacheReader = new NetByteCacheReader();
    }

    protected override void Poll()
    {
        if (_items == null || _items.Count == 0) return;
        byte[] cache = (byte[])_cacheReader.Cache;
        int offset = 0;
        foreach (PDUArea area in _rangeList)
        {
            byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据                
            if (rcvBytes == null)
            {
                //_plcReader.Connect();
                continue;
            }
            else
            {
                int index = area.StartIndex;//index指向_items中的Tag元数据
                int count = index + area.Count;
                while (index < count)
                {
                    DeviceAddress addr = _items[index].Address;
                    int iByte = addr.CacheIndex;
                    int iByte1 = iByte - offset;
                    if (addr.VarType == DataType.BOOL)
                    {
                        int tmp = rcvBytes[iByte1] ^ cache[iByte];
                        DeviceAddress next = addr;
                        if (tmp != 0)
                        {
                            while (addr.Start == next.Start)
                            {
                                if ((tmp & 1 << next.Bit) > 0) _changedList.Add(index);
                                if (++index < count)
                                    next = _items[index].Address;
                                else
                                    break;
                            }
                        }
                        else
                        {
                            while (addr.Start == next.Start && ++index < count)
                            {
                                next = _items[index].Address;
                            }
                        }
                    }
                    else
                    {
                        ushort size = addr.DataSize;
                        for (int i = 0; i < size; i++)
                        {
                            if (iByte1 + i < rcvBytes.Length && rcvBytes[iByte1 + i] != cache[iByte + i])
                            {
                                _changedList.Add(index);
                                break;
                            }
                        }
                        index++;
                    }
                }
                for (int j = 0; j < rcvBytes.Length; j++)
                    cache[j + offset] = rcvBytes[j];//将PLC读取的数据写入到CacheReader中
            }
            offset += rcvBytes.Length;
        }
    }
}

public sealed class NetShortGroup : PLCGroup
{
    public NetShortGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
    {
        _id = id;
        _name = name;
        _updateRate = updateRate;
        _isActive = active;
        _plcReader = plcReader;
        _server = _plcReader.Parent;
        _timer = new Timer();
        _changedList = new List<int>();
        _cacheReader = new NetShortCacheReader();
    }

    protected override unsafe void Poll()
    {
        short[] cache = (short[])_cacheReader.Cache;
        int offset = 0;
        foreach (PDUArea area in _rangeList)
        {
            byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据  
            if (rcvBytes == null || rcvBytes.Length == 0)
            {
                offset += (area.Len + 1) / 2;
                //_plcReader.Connect();
                continue;
            }
            else
            {
                int len = rcvBytes.Length / 2;
                fixed (byte* p1 = rcvBytes)
                {
                    short* prcv = (short*)p1;
                    int index = area.StartIndex;//index指向_items中的Tag元数据
                    int count = index + area.Count;
                    while (index < count)
                    {
                        DeviceAddress addr = _items[index].Address;
                        int iShort = addr.CacheIndex;
                        int iShort1 = iShort - offset;
                        if (addr.VarType == DataType.BOOL)
                        {
                            if (addr.ByteOrder.HasFlag(ByteOrder.Network)) prcv[iShort1] = IPAddress.HostToNetworkOrder(prcv[iShort1]);
                            int tmp = prcv[iShort1] ^ cache[iShort];
                            DeviceAddress next = addr;
                            if (tmp != 0)
                            {
                                while (addr.Start == next.Start)
                                {
                                    if ((tmp & 1 << next.Bit) > 0) _changedList.Add(index);
                                    if (++index < count)
                                        next = _items[index].Address;
                                    else
                                        break;
                                }
                            }
                            else
                            {
                                while (addr.Start == next.Start && ++index < count)
                                {
                                    next = _items[index].Address;
                                }
                            }
                        }
                        else
                        {
                            if (addr.DataSize <= 2)
                            {
                                if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
                            }
                            else
                            {
                                int size = addr.DataSize / 2;
                                for (int i = 0; i < size; i++)
                                {
                                    if (prcv[iShort1 + i] != cache[iShort + i])
                                    {
                                        _changedList.Add(index);
                                        break;
                                    }
                                }
                            }
                            index++;
                        }
                    }
                    for (int j = 0; j < len; j++)
                    {
                        cache[j + offset] = prcv[j];
                    }//将PLC读取的数据写入到CacheReader中
                }
                offset += len;
            }
        }
    }
}

public sealed class ShortGroup : PLCGroup
{
    public ShortGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
    {
        _id = id;
        _name = name;
        _updateRate = updateRate;
        _isActive = active;
        _plcReader = plcReader;
        _server = _plcReader.Parent;
        _timer = new Timer();
        _changedList = new List<int>();
        _cacheReader = new ShortCacheReader();
    }

    protected override unsafe void Poll()
    {
        short[] cache = (short[])_cacheReader.Cache;
        int k = 0;
        foreach (PDUArea area in _rangeList)
        {
            byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据  
            if (rcvBytes == null)
            {
                k += (area.Len + 1) / 2;
                continue;
            }
            else
            {
                int len = rcvBytes.Length / 2;
                fixed (byte* p1 = rcvBytes)
                {
                    short* prcv = (short*)p1;
                    int index = area.StartIndex;//index指向_items中的Tag元数据
                    int count = index + area.Count;
                    while (index < count)
                    {
                        DeviceAddress addr = _items[index].Address;
                        int iShort = addr.CacheIndex;
                        int iShort1 = iShort - k;
                        if (addr.VarType == DataType.BOOL)
                        {
                            int tmp = prcv[iShort1] ^ cache[iShort];
                            DeviceAddress next = addr;
                            if (tmp != 0)
                            {
                                while (addr.Start == next.Start)
                                {
                                    if ((tmp & 1 << next.Bit) > 0) _changedList.Add(index);
                                    if (++index < count)
                                        next = _items[index].Address;
                                    else
                                        break;
                                }
                            }
                            else
                            {
                                while (addr.Start == next.Start && ++index < count)
                                {
                                    next = _items[index].Address;
                                }
                            }
                        }
                        else
                        {
                            if (addr.ByteOrder.HasFlag(ByteOrder.BigEndian))
                            {
                                for (int i = 0; i < addr.DataSize / 2; i++)
                                {
                                    prcv[iShort1 + i] = IPAddress.HostToNetworkOrder(prcv[iShort1 + i]);
                                }
                            }
                            if (addr.DataSize <= 2)
                            {
                                if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
                            }
                            else
                            {
                                int size = addr.DataSize / 2;
                                for (int i = 0; i < size; i++)
                                {
                                    if (prcv[iShort1 + i] != cache[iShort + i])
                                    {
                                        _changedList.Add(index);
                                        break;
                                    }
                                }
                            }
                            index++;
                        }
                    }
                    for (int j = 0; j < len; j++)
                    {
                        cache[j + k] = prcv[j];
                    }//将PLC读取的数据写入到CacheReader中
                }
                k += len;
            }
        }
    }

}
